package com.courir.data;

import static com.courir.data.Altersgruppe.*;

import java.util.Arrays;
import java.util.Map;
import java.util.SortedSet;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.val;

import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;

/**
 * Der Lauf.
 */
@RequiredArgsConstructor
public enum Lauf {
	/** Nicht angegeben. */
	NA(-1, ""),
	/** */
	Bambini(1, "Bambini"),
	/** D */
	Schueler(2, "Schueler 800m", M08, M09),
	/** */
	Jugend(4, "Jugend 2000m"),
	/** */
	Jedermann(7, "Jedermannlauf"),
	/** */
	Volkslauf(8, "Volkslauf", Erwachsene),
	/** */
	Halbmarathon(9, "Halbmarathon", Erwachsene);

	private static final Map<Integer, Lauf> Index = Maps.uniqueIndex(
			Arrays.asList(Lauf.values()), new Function<Lauf, Integer>() {
				public Integer apply(Lauf l) {
					return l.number;
				}
			});

	public static Lauf of(int number) {
		return Objects.firstNonNull(Index.get(number), NA);
	}

	/** Identifikationsnummer. */
	private final int number;

	/** Name des Laufs (für Ausdrucke u.ä.). */
	private final String name;

	@Getter
	private final SortedSet<Altersgruppe> altersgruppen;

	Lauf(int number, String name, Altersgruppe... altersgruppen) {
		this(number, name, ImmutableSortedSet.copyOf(altersgruppen));
	}

	public String toString() {
		return name;
	}

	/**
	 * passendste Altersgruppe für ein Alter liefern, None falls es keine
	 * Gruppen gibt.
	 */
	public Altersgruppe get(Geschlecht geschlecht, int age) {
		val i = altersgruppen.iterator();
		if (!i.hasNext()) {
			return None;
		}
		// passendste Gruppe finden!
		Altersgruppe ag = i.next();
		while (i.hasNext()) {
			val ag2 = i.next();
			if (!geschlecht.equals(ag2.getGeschlecht())) {
				continue;
			}
			if (ag2.getAlter() > age) {
				// letztes element passte am besten
				return ag;
			}
			ag = ag2;
		}
		return ag;
	}

	/**
	 * Prüft ob es sich hierbei um den "leeren" Lauf handelt.
	 */
	public boolean isEmpty() {
		return this.equals(NA);
	}
}